﻿using StackExchange.Redis;
using SXICE.Core.Helpers;
using SXICE.Core.Infrastructure;
using System;
using System.Collections.Concurrent;

namespace SXICE.DistributedCache
{
    /// <summary>
    /// Redis连接管理器
    /// </summary>
    public class RedisConnectionHelper
    {
        private static string redisConnectionString;
        private static readonly object locker = new object();
        private static ConnectionMultiplexer _instance;
        private static ILog log;
        private static int dbIndex;

        internal static void Init()
        {
            var config = RuntimeHelper.Resolve<RedisConfigs>();
            redisConnectionString = config.ConnectionString;
            dbIndex = config.DBIndex;
            log = RuntimeHelper.Resolve<ILog>();
        }

        /// <summary>
        /// 单例获取
        /// </summary>
        public static IDatabase DB
        {
            get
            {
                if (_instance == null)
                    lock (locker)
                        if (_instance == null || !_instance.IsConnected)
                            _instance = GetManager();
                return _instance.GetDatabase(dbIndex);
            }
        }

        /// <summary>
        /// 获取订阅者
        /// </summary>
        public static ISubscriber Subscriber
        {
            get
            {
                if (_instance == null)
                    lock (locker)
                        if (_instance == null || !_instance.IsConnected)
                            _instance = GetManager();
                return _instance.GetSubscriber();
            }
        }

        private static ConnectionMultiplexer GetManager(string connectionString = null)
        {
            connectionString = connectionString ?? redisConnectionString;
            var connect = ConnectionMultiplexer.Connect(connectionString);
            //注册如下事件
            connect.ConnectionFailed += MuxerConnectionFailed;
            connect.ConnectionRestored += MuxerConnectionRestored;
            connect.ErrorMessage += MuxerErrorMessage;
            connect.ConfigurationChanged += MuxerConfigurationChanged;
            connect.HashSlotMoved += MuxerHashSlotMoved;
            connect.InternalError += MuxerInternalError;
            return connect;
        }

        #region 事件

        /// <summary>
        /// 配置更改时
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void MuxerConfigurationChanged(object sender, EndPointEventArgs e)
        {
            Console.WriteLine("Configuration changed: " + e.EndPoint);
        }

        /// <summary>
        /// 发生错误时
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void MuxerErrorMessage(object sender, RedisErrorEventArgs e)
        {
            log.Error(new Exception(e.Message));
        }

        /// <summary>
        /// 重新建立连接之前的错误
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void MuxerConnectionRestored(object sender, ConnectionFailedEventArgs e)
        {
        }

        /// <summary>
        /// 连接失败 ， 如果重新连接成功你将不会收到这个通知
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void MuxerConnectionFailed(object sender, ConnectionFailedEventArgs e)
        {
            log.Error(e.Exception);
        }

        /// <summary>
        /// 更改集群
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void MuxerHashSlotMoved(object sender, HashSlotMovedEventArgs e)
        {
            Console.WriteLine("HashSlotMoved:NewEndPoint" + e.NewEndPoint + ", OldEndPoint" + e.OldEndPoint);
        }

        /// <summary>
        /// redis类库错误
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void MuxerInternalError(object sender, InternalErrorEventArgs e)
        {
            log.Error(e.Exception);
        }

        #endregion 事件
    }
}
